home *** CD-ROM | disk | FTP | other *** search
- PROGRAM HCalc; { By Jeff Duntemann; Update of 10/31/91 }
- { Requires Turbo Pascal 6.0! }
-
- USES App,Dialogs,Objects,Views,Menus,Drivers,
- FInput, { By Allen Bauer; on CompuServe BPROGA }
- Mortgage; { By Jeff Duntemann; from DDJ 10/91 }
-
- CONST
- cmNewMortgage = 199;
- cmExtraPrin = 198;
- cmCloseAll = 197;
- cmCloseBC = 196;
- cmPrintSummary = 195;
- WindowCount : Integer = 0;
-
- TYPE
- MortgageDialogData =
- RECORD
- PrincipalData : Real;
- InterestData : Real;
- PeriodsData : Integer;
- END;
-
- ExtraPrincipalDialogData =
- RECORD
- PaymentNumber : Integer;
- ExtraDollars : Real;
- END;
-
- THouseCalcApp =
- OBJECT(TApplication)
- InitDialog : PDialog; { Dialog for initializing a mortgage }
- ExtraDialog : PDialog; { Dialog for entering extra principal }
- CONSTRUCTOR Init;
- PROCEDURE InitMenuBar; VIRTUAL;
- PROCEDURE CloseAll;
- PROCEDURE HandleEvent(VAR Event : TEvent); VIRTUAL;
- PROCEDURE NewMortgage;
- END;
-
- PMortgageTopInterior = ^TMortgageTopInterior;
- TMortgageTopInterior =
- OBJECT(TView)
- Mortgage : PMortgage;
- CONSTRUCTOR Init(VAR Bounds : TRect);
- PROCEDURE Draw; VIRTUAL;
- END;
-
-
- PMortgageBottomInterior = ^TMortgageBottomInterior;
- TMortgageBottomInterior =
- OBJECT(TScroller)
- { Points to Mortgage object owned by TMortgageView }
- Mortgage : PMortgage;
- CONSTRUCTOR Init(VAR Bounds : TRect;
- AHScrollBar, AVScrollbar : PScrollBar);
- PROCEDURE Draw; VIRTUAL;
- END;
-
- PMortgageView = ^TMortgageView;
- TMortgageView =
- OBJECT(TWindow)
- Mortgage : TMortgage;
- CONSTRUCTOR Init(VAR Bounds : TRect;
- ATitle : TTitleStr;
- ANumber : Integer;
- InitMortgageData :
- MortgageDialogData);
- PROCEDURE HandleEvent(Var Event : TEvent); VIRTUAL;
- PROCEDURE ExtraPrincipal;
- PROCEDURE PrintSummary;
- DESTRUCTOR Done; VIRTUAL;
- END;
-
-
- CONST
- DefaultMortgageData : MortgageDialogData =
- (PrincipalData : 100000;
- InterestData : 10.0;
- PeriodsData : 360);
-
-
- VAR
- HouseCalc : THouseCalcApp; { This is the application object itself }
-
-
-
- {------------------------------}
- { METHODS: THouseCalcApp }
- {------------------------------}
-
-
- CONSTRUCTOR THouseCalcApp.Init;
-
- VAR
- R : TRect;
- aView : PView;
-
- BEGIN
- TApplication.Init; { Always call the parent's constructor first! }
-
- { Create the dialog for initializing a mortgage: }
- R.Assign(20,5,60,16);
- InitDialog := New(PDialog,Init(R,'Define Mortgage Parameters'));
- WITH InitDialog^ DO
- BEGIN
- { First item in the dialog box is input line for principal: }
- R.Assign(3,3,13,4);
- aView := New(PFInputLine,Init(R,8,DRealSet,DReal,0));
- Insert(aView);
- R.Assign(2,2,12,3);
- Insert(New(PLabel,Init(R,'Principal',aView)));
-
- { Next is the input line for interest rate: }
- R.Assign(17,3,26,4);
- aView := New(PFInputLine,Init(R,6,DRealSet,DReal,3));
- Insert(aView);
- R.Assign(16,2,25,3);
- Insert(New(PLabel,Init(R,'Interest',aView)));
- R.Assign(26,3,27,4); { Add a static text "%" sign }
- Insert(New(PStaticText,Init(R,'%')));
-
- { Up next is the input line for number of periods: }
- R.Assign(31,3,36,4);
- aView := New(PFInputLine,Init(R,3,DUnsignedSet,DInteger,0));
- Insert(aView);
- R.Assign(29,2,37,3);
- Insert(New(PLabel,Init(R,'Periods',aView)));
-
- { These are standard buttons for the OK and Cancel commands: }
- R.Assign(8,8,16,10);
- Insert(New(PButton,Init(R,'~O~K',cmOK,bfDefault)));
- R.Assign(22,8,32,10);
- Insert(New(PButton,Init(R,'Cancel',cmCancel,bfNormal)));
- END;
-
- { Create the dialog for adding additional principal to a payment: }
- R.Assign(20,5,60,16);
- ExtraDialog := New(PDialog,Init(R,'Apply Extra Principal to Mortgage'));
- WITH ExtraDialog^ DO
- BEGIN
- { First item in the dialog is the payment number to which }
- { we're going to apply the extra principal: }
- R.Assign(9,3,18,4);
- aView := New(PFInputLine,Init(R,6,DUnsignedSet,DInteger,0));
- Insert(aView);
- R.Assign(3,2,12,3);
- Insert(New(PLabel,Init(R,'Payment #',aView)));
-
- { Next item in the dialog box is input line for extra principal: }
- R.Assign(23,3,33,4);
- aView := New(PFInputLine,Init(R,8,DRealSet,DReal,2));
- Insert(aView);
- R.Assign(20,2,35,3);
- Insert(New(PLabel,Init(R,'Extra Principal',aView)));
-
- { These are standard buttons for the OK and Cancel commands: }
- R.Assign(8,8,16,10);
- Insert(New(PButton,Init(R,'~O~K',cmOK,bfDefault)));
- R.Assign(22,8,32,10);
- Insert(New(PButton,Init(R,'Cancel',cmCancel,bfNormal)));
- END;
-
- END;
-
-
- { This method sends out a broadcast message to all views. Only the
- { mortgage windows know how to respond to it, so when cmCloseBC is
- { issued, only the mortgage windows react--by closing. }
-
- PROCEDURE THouseCalcApp.CloseAll;
-
- VAR
- Who : Pointer;
-
- BEGIN
- Who := Message(Desktop,evBroadcast,cmCloseBC,@Self);
- END;
-
-
- PROCEDURE THouseCalcApp.HandleEvent(VAR Event : TEvent);
-
- BEGIN
- TApplication.HandleEvent(Event);
- IF Event.What = evCommand THEN
- BEGIN
- CASE Event.Command OF
- cmNewMortgage : NewMortgage;
- cmCloseAll : CloseAll;
- ELSE
- Exit;
- END; { CASE }
- ClearEvent(Event);
- END;
- END;
-
-
- PROCEDURE THouseCalcApp.NewMortgage;
-
- VAR
- Code : Integer;
- R : TRect;
- Control : Word;
- ThisMortgage : PMortgageView;
- InitMortgageData : MortgageDialogData;
-
- BEGIN
- { First we need a dialog to get the intial mortgage values from }
- { the user. The dialog appears *before* the mortgage window! }
- WITH InitMortgageData DO
- BEGIN
- PrincipalData := 100000;
- InterestData := 10.0;
- PeriodsData := 360;
- END;
- InitDialog^.SetData(InitMortgageData);
- Control := Desktop^.ExecView(InitDialog);
- IF Control <> cmCancel THEN { Create a new mortgage object: }
- BEGIN
- R.Assign(5,5,45,20);
- Inc(WindowCount);
- { Get data from the initial mortgage dialog: }
- InitDialog^.GetData(InitMortgageData);
- { Call the constructor for the mortgage window: }
- ThisMortgage :=
- New(PMortgageView,Init(R,'Mortgage',WindowCount,
- InitMortgageData));
-
- { Insert the mortgage window into the desktop: }
- Desktop^.Insert(ThisMortgage);
- END;
- END;
-
-
- PROCEDURE THouseCalcApp.InitMenuBar;
-
- VAR
- R : TRect;
-
- BEGIN
- GetExtent(R);
- R.B.Y := R.A.Y + 1; { Define 1-line menu bar }
-
- MenuBar := New(PMenuBar,Init(R,NewMenu(
- NewSubMenu('~M~ortgage',hcNoContext,NewMenu(
- NewItem('~N~ew','F6',kbF6,cmNewMortgage,hcNoContext,
- NewItem('~E~xtra Principal ','',0,cmExtraPrin,hcNoContext,
- NewItem('~C~lose all','F7',kbF7,cmCloseAll,hcNoContext,
- NewItem('E~x~it','Alt-X',kbAltX,cmQuit,hcNoContext,
- NIL))))),
- NIL)
- )));
- END;
-
-
- {---------------------------------}
- { METHODS: TMortgageTopInterior }
- {---------------------------------}
-
- CONSTRUCTOR TMortgageTopInterior.Init(VAR Bounds : TRect);
-
- BEGIN
- TView.Init(Bounds); { Call ancestor's constructor }
- GrowMode := gfGrowHiX; { Permits pane to grow in X but not Y }
- END;
-
-
- PROCEDURE TMortgageTopInterior.Draw;
-
- VAR
- YRun : Integer;
- Color : Byte;
- B : TDrawBuffer;
- STemp : String[20];
-
- BEGIN
- Color := GetColor(1);
- MoveChar(B,' ',Color,Size.X); { Clear the buffer to spaces }
- MoveStr(B,' Principal Interest Periods',Color);
- WriteLine(0,0,Size.X,1,B);
-
- MoveChar(B,' ',Color,Size.X); { Clear the buffer to spaces }
- { Here we convert payment data to strings for display: }
- Str(Mortgage^.Principal:7:2,STemp);
- MoveStr(B[2],STemp,Color); { At beginning of buffer B }
- Str(Mortgage^.Interest*100:7:2,STemp);
- MoveStr(B[14],STemp,Color); { At position 14 of buffer B }
- Str(Mortgage^.Periods:4,STemp);
- MoveStr(B[27],STemp,Color); { At position 27 of buffer B }
- WriteLine(0,1,Size.X,1,B);
-
- MoveChar(B,' ',Color,Size.X); { Clear the buffer to spaces }
- MoveStr(B,
- ' Extra Principal Interest',
- Color);
- WriteLine(0,2,Size.X,1,B);
-
- MoveChar(B,' ',Color,Size.X); { Clear the buffer to spaces }
- MoveStr(B,
- 'Paymt # Prin. Int. Balance Principal So far So far ',
- Color);
- WriteLine(0,3,Size.X,1,B);
-
- END;
-
-
- {------------------------------------}
- { METHODS: TMortgageBottomInterior }
- {------------------------------------}
-
- CONSTRUCTOR TMortgageBottomInterior.Init(VAR Bounds : TRect;
- AHScrollBar, AVScrollBar :
- PScrollBar);
-
- BEGIN
- { Call ancestor's constructor: }
- TScroller.Init(Bounds,AHScrollBar,AVScrollBar);
- GrowMode := gfGrowHiX + gfGrowHiY;
- Options := Options OR ofFramed;
- END;
-
-
- PROCEDURE TMortgageBottomInterior.Draw;
-
- VAR
- Color : Byte;
- B : TDrawBuffer;
- YRun : Integer;
- STemp : String[20];
-
- BEGIN
- Color := GetColor(1);
- FOR YRun := 0 TO Size.Y-1 DO
- BEGIN
- MoveChar(B,' ',Color,80); { Clear the buffer to spaces }
- Str(Delta.Y+YRun+1:4,STemp);
- MoveStr(B,STemp+':',Color); { At beginning of buffer B }
- { Here we convert payment data to strings for display: }
- Str(Mortgage^.Payments^[Delta.Y+YRun+1].PayPrincipal:7:2,STemp);
- MoveStr(B[6],STemp,Color); { At beginning of buffer B }
- Str(Mortgage^.Payments^[Delta.Y+YRun+1].PayInterest:7:2,STemp);
- MoveStr(B[15],STemp,Color); { At position 15 of buffer B }
- Str(Mortgage^.Payments^[Delta.Y+YRun+1].Balance:10:2,STemp);
- MoveStr(B[24],STemp,Color); { At position 24 of buffer B }
- { There isn't an extra principal value for every payment, so }
- { display the value only if it is nonzero: }
- STemp := '';
- IF Mortgage^.Payments^[Delta.Y+YRun+1].ExtraPrincipal > 0
- THEN
- Str(Mortgage^.Payments^[Delta.Y+YRun+1].ExtraPrincipal:10:2,STemp);
- MoveStr(B[37],STemp,Color); { At position 37 of buffer B }
- Str(Mortgage^.Payments^[Delta.Y+YRun+1].PrincipalSoFar:10:2,STemp);
- MoveStr(B[50],STemp,Color); { At position 50 of buffer B }
- Str(Mortgage^.Payments^[Delta.Y+YRun+1].InterestSoFar:10:2,STemp);
- MoveStr(B[64],STemp,Color); { At position 64 of buffer B }
- { Here we write the line to the window, taking into account the }
- { state of the X scroll bar: }
- WriteLine(0,YRun,Size.X,1,B[Delta.X]);
- END;
- END;
-
-
- {------------------------------}
- { METHODS: TMortgageView }
- {------------------------------}
-
- CONSTRUCTOR TMortgageView.Init(VAR Bounds : TRect;
- ATitle : TTitleStr;
- ANumber : Integer;
- InitMortgageData :
- MortgageDialogData);
- VAR
- TopInterior : PMortgageTopInterior;
- BottomInterior : PMortgageBottomInterior;
- HScrollBar,VScrollBar : PScrollBar;
- R,S : TRect;
-
- BEGIN
- TWindow.Init(Bounds,ATitle,ANumber); { Call ancestor's constructor }
- { Call the Mortgage object's constructor using dialog data: }
- WITH InitMortgageData DO
- Mortgage.Init(PrincipalData,
- InterestData / 100,
- PeriodsData,
- 12);
-
- { Here we set up a window with *two* interiors, one scrollable, one }
- { static. It's all in the way that you define the bounds, mostly: }
- GetClipRect(Bounds); { Get bounds for interior of view }
- Bounds.Grow(-1,-1); { Shrink those bounds by 1 for both X & Y }
-
- { Define a rectangle to embrace the upper of the two interiors: }
- R.Assign(Bounds.A.X,Bounds.A.Y,Bounds.B.X,Bounds.A.Y+4);
- TopInterior := New(PMortgageTopInterior,Init(R));
- TopInterior^.Mortgage := @Mortgage;
- Insert(TopInterior);
-
- { Define a rectangle to embrace the lower of two interiors: }
- R.Assign(Bounds.A.X,Bounds.A.Y+5,Bounds.B.X,Bounds.B.Y);
-
- { Create scroll bars for both mouse & keyboard input: }
- VScrollBar := StandardScrollBar(sbVertical + sbHandleKeyboard);
- { We have to adjust vertical bar to fit bottom interior: }
- VScrollBar^.Origin.Y := R.A.Y; { Adjust top Y value }
- VScrollBar^.Size.Y := R.B.Y - R.A.Y; { Adjust size }
- { The horizontal scroll bar, on the other hand, is standard: }
- HScrollBar := StandardScrollBar(sbHorizontal + sbHandleKeyboard);
-
- { Create bottom interior object with scroll bars: }
- BottomInterior :=
- New(PMortgageBottomInterior,Init(R,HScrollBar,VScrollBar));
- { Make copy of pointer to mortgage object: }
- BottomInterior^.Mortgage := @Mortgage;
- { Set the limits for the scroll bars: }
- BottomInterior^.SetLimit(80,InitMortgageData.PeriodsData);
- { Insert the interior into the window: }
- Insert(BottomInterior);
- END;
-
-
- PROCEDURE TMortgageView.HandleEvent(Var Event : TEvent);
-
- BEGIN
- TWindow.HandleEvent(Event);
- IF Event.What = evCommand THEN
- BEGIN
- CASE Event.Command OF
- cmExtraPrin : ExtraPrincipal;
- cmPrintSummary : PrintSummary;
- ELSE
- Exit;
- END; { CASE }
- ClearEvent(Event);
- END
- ELSE
- IF Event.What = evBroadcast THEN
- CASE Event.Command OF
- cmCloseBC : Done
- END; { CASE }
- END;
-
-
- PROCEDURE TMortgageView.ExtraPrincipal;
-
- VAR
- Control : Word;
- ExtraPrincipalData : ExtraPrincipalDialogData;
-
- BEGIN
- { Execute the "extra principal" dialog box: }
- Control := Desktop^.ExecView(HouseCalc.ExtraDialog);
- IF Control <> cmCancel THEN { Update the active mortgage window: }
- BEGIN
- { Get data from the extra principal dialog: }
- HouseCalc.ExtraDialog^.GetData(ExtraPrincipalData);
- Mortgage.Payments^[ExtraPrincipalData.PaymentNumber].ExtraPrincipal :=
- ExtraPrincipalData.ExtraDollars;
- Mortgage.Recalc; { Recalculate the amortization table... }
- Redraw; { ...and redraw the mortgage window }
- END;
- END;
-
-
- PROCEDURE TMortgageView.PrintSummary;
-
- BEGIN
- END;
-
-
- DESTRUCTOR TMortgageView.Done;
-
- BEGIN
- Mortgage.Done; { Dispose of the mortgage object's memory }
- TWindow.Done; { Call parent's destructor to dispose of window }
- END;
-
-
-
- BEGIN
- HouseCalc.Init;
- HouseCalc.Run;
- HouseCalc.Done;
- END.